home *** CD-ROM | disk | FTP | other *** search
/ Trading on the Edge / Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin / mac / Mac_Files / Software Utilities / NN PreProcessing / FINBLD.C < prev    next >
C/C++ Source or Header  |  1992-08-25  |  28KB  |  883 lines

  1. /* 19:53 12-Aug-92  (finbld.c)  Build Financial Data-base */
  2.  
  3. #include "fin.h"
  4.  
  5. /************************************************************************
  6.  * Copyright(C) 1992 High-Tech Communications.                          *
  7.  * 103 Buckskin Court, Sewickley, PA 15143                              *
  8.  *                                                                      *
  9.  * Written by Casimir C. Klimasauskas                                   *
  10.  *                                                                      *
  11.  * All rights reserved.  No part of this program may be reproduced,     *
  12.  * stored in a retrieval system, or tramsmitted, in any form or by any  *
  13.  * means, electronic, mechanical, photocopying, recording or otherwise  *
  14.  * without the prior written permission of the copyright owner,         *
  15.  * High-Tech Communications.                                            *
  16.  *                                                                      *
  17.  * These programs are supplied on an "as-is" basis with no warranties   *
  18.  * of fitness or operability, either express or implied.                *
  19.  *                                                                      *
  20.  ************************************************************************
  21.  */
  22.  
  23. /************************************************************************
  24.  *                                    *
  25.  *    FinBld - Generate Merged Financial Data-Base            *
  26.  *                                    *
  27.  ************************************************************************
  28.     This routine performs the following functions:
  29.     - parse a Compu-Serve session
  30.     - load an existing data-base [optional]
  31.     - merge the Compu-Serve session sections together
  32.     - save the merged data-base
  33.  
  34.     The format of the merged data-base is:
  35.  
  36.     \t    ticker    ticker    ticker    ...
  37.     date    open    high    low    ...
  38.     ... data ...
  39.  
  40.     It uses tab-separated fields so that the file can be easily
  41.     read into excel or lotus 1-2-3.
  42.  */
  43.  
  44. /* --- The following data structures are used for processing ticker file ---
  45.  
  46.     Current Record Data Buffer
  47.     Current Record Transformed Data Buffer
  48.     Current Record Data Description
  49.     Field    (Ticker, Field, Data Ptr (CRDB))
  50.     Field    ...
  51.  
  52.     Input Data-Base Data Buffer
  53.     Input Date-Base Description
  54.     Field    (Ticker, Field, Data Ptr (input DBDB))
  55.     Field    ...
  56.  
  57.     Output Data-Base Description
  58.         Field    (Ticker, Field, IDBDB Field Ptr, CRDB Field Ptr)
  59.     Field    ...
  60.  
  61. */
  62.  
  63. typedef struct _ifield  {    /* field in a ticker (Current Record/Input DB) */
  64.     char    *FTickCP;    /* ticker symbol */
  65.     char    *FSymCP;    /* field name */
  66.     char    *FDataCP;    /* data pointer */
  67.     int     FStartI;    /* start position */
  68.     int     FLenI;        /* length of field */
  69. } IFIELD;
  70.  
  71. typedef struct _ofield    {    /* output data-base field */
  72.     char    *FTickCP;    /* ticker symbol */
  73.     char    *FSymCP;    /* field name */
  74.     IFIELD    *FCRecTP;    /* current record */
  75.     IFIELD    *FDRecTP;    /* data-base record */
  76. } OFIELD;
  77.  
  78. /************************************************************************
  79.  *                                    *
  80.  *        Data-Base Manipulation Routines                *
  81.  *                                    *
  82.  ************************************************************************
  83.     DBGetRecI()    - read a raw data record from data-base
  84.     DBClearInitV()    - Clear all data-base fields
  85.     DBCheckInitI()    - See if dynamic areas are initialized
  86.  
  87.     DBOpenInI()    - open data-base & build basic structures
  88.     DBReadInI()    - read next field into buffer
  89.     DBWriteI()    - write data-base output
  90.     DBCloseI()    - close data-base input/output
  91.  */
  92.  
  93. char    *CRRawBufCP    = {0};    /* current record raw data buffer */
  94. char    *CRBufCP    = {0};    /* current record data buffer */
  95. char    *DRBufCP    = {0};    /* data-base record current record */
  96.  
  97. char     CRDate[10]    = {0};    /* current record date */
  98. char     DBDate[10]    = {0};    /* data-base date */
  99.  
  100. IFIELD    *CRecTF        = {0};    /* current record field table */
  101. IFIELD    *DRecTF        = {0};    /* data base record field table */
  102. OFIELD    *ORecTF        = {0};    /* output data-base table */
  103.  
  104. int     CRecNI        = {0};    /* # of items in CRecTF */
  105. int     DRecNI        = {0};    /* # of items in DRecTF */
  106. int     ORecNI        = {0};    /* # of items in ORecTF */
  107.  
  108. FILE    *IDBFP        = {0};    /* input data-base file pointer */
  109. FILE    *ODBFP        = {0};    /* output data-base file pointer */
  110.  
  111. int     IsCREOF    = {0};    /* current record "eof" */
  112. int     IsDBEOF    = {0};    /* data-base record "eof" */
  113.  
  114. /* --- DBGetRecI() ---
  115.  *    Read a raw data record from the data-base
  116.  */
  117.  
  118. int DBGetRecI( bufCP, buflI, idbFP, eofIP )    /* read a data-base record */
  119. char        *bufCP;    /* input buffer */
  120. int         buflI;    /* buffer length */
  121. FILE        *idbFP;    /* input file pointer */
  122. int        *eofIP;    /* end of file input pointer */
  123. {
  124.     register char    *sp;    /* work string pointer */
  125.  
  126.     if ( idbFP == (FILE *)0 || feof(idbFP) || ferror(idbFP) ||
  127.      (eofIP != (int *)0 && *eofIP != 0) )
  128.     goto Eof;        /* no more to read */
  129.  
  130.     while( (sp = fgets( bufCP, buflI-1, idbFP )) != (char *)0 ) {
  131.     while( *sp && *sp <= ' ' ) sp++;    /* skip spaces */
  132.     if ( *sp != 0 && *sp != '!' ) {        /* check for blank line */
  133.         for(; *sp; sp++ )            /* kill eol characters */
  134.         if ( *sp == '\r' || *sp == '\n' ) break;
  135.         *sp = 0;
  136.         return( 0 );    /* all is well */
  137.     }
  138.     }
  139. Eof:
  140.     if ( eofIP != (int *)0 ) *eofIP = 1;    /* end of file hit */
  141.     return( -1 );
  142. }
  143.  
  144. /* --- DBClearInitV() ---
  145.  *    Clear all of the structures associated with the data-base
  146.  */
  147.  
  148. void DBClearInitV()    /* clear out data-base structures */
  149. {
  150.     unsigned    BlkSU;        /* size of block to clear */
  151.  
  152.     if ( CRRawBufCP != (char *)0 ) {
  153.     BlkSU = 3 * MAXFL + 3;
  154.     memset( (void *)CRRawBufCP, 0, BlkSU );
  155.     }
  156.     if ( CRecTF != (IFIELD *)0 ) {
  157.     BlkSU = MAXFIELD * (sizeof(IFIELD)+sizeof(IFIELD)+sizeof(OFIELD));
  158.     memset( (void *)CRecTF, 0, BlkSU );
  159.     }
  160.     IsCREOF = IsDBEOF = 1;        /* force EOF on all */
  161.     CRecNI = DRecNI = ORecNI = 0;    /* clear tables */
  162.     return;
  163. }
  164.  
  165. /* --- DBCheckInitI() ---
  166.  *    Check to see that all data structures are allocated.
  167.  *    If not, allocate and initialize them.
  168.  */
  169.  
  170. int DBCheckInitI()    /* check to see data-areas initialized */
  171. {
  172.     static int    InitedI = {0};    /* flag = 1 if initialized */
  173.     unsigned    BlkSU;        /* block size */
  174.  
  175.     if ( !InitedI ) {
  176.     BlkSU = 3 * MAXFL + 3;
  177.     if ( (CRRawBufCP = (char *)malloc( BlkSU )) == (char *)0 ) {
  178.         fprintf( stderr, "Could not allocate space for data buffers\n" );
  179.         exit( 4 );
  180.     }
  181.     CRBufCP = &CRRawBufCP[ MAXFL + 1 ];
  182.     DRBufCP = &CRBufCP[ MAXFL + 1 ];
  183.  
  184.     BlkSU = MAXFIELD*(sizeof(IFIELD)+sizeof(IFIELD)+sizeof(OFIELD));
  185.     if ( (CRecTF = (IFIELD *)malloc( BlkSU ) ) == (IFIELD *)0 ) {
  186.         fprintf( stderr, "Could not allocate memory for fields\n" );
  187.         exit( 5 );
  188.     }
  189.     DRecTF = &CRecTF[ MAXFIELD ];
  190.     ORecTF = (OFIELD *)(&DRecTF[ MAXFIELD ]);
  191.     DBClearInitV();
  192.  
  193.     InitedI = 1;
  194.     return( 1 );
  195.     }
  196.     return( 0 );
  197. }
  198.  
  199. /* --- DBOpenInI() ---
  200.  *    Open the master data-base file for input.
  201.  *    Build all of the data structures which describe it.
  202.  */
  203.  
  204. int DBOpenInI( dbnCP )        /* open up an existing data-base */
  205. char        *dbnCP;        /* name of data-base to open */
  206. {
  207.     char    *sp, *ap;    /* string pointer */
  208.     int         lc;        /* last character */
  209.     int         wxI;        /* work index */
  210.  
  211.     if ( ! DBCheckInitI() )        /* check memory allocation */
  212.     DBClearInitV();            /* clear if already allocated */
  213.     if ( IDBFP != (FILE *)0 ) fclose( IDBFP );
  214.     if ( (IDBFP = fopen( dbnCP, "r" )) == (FILE *)0 )
  215.         return( -1 );            /* could not open file */
  216.  
  217.     /* --- Opened, read in the header information --- */
  218.     IsDBEOF = 0;
  219.  
  220.     /* --- parse ticker symbols --- */
  221.     if ( DBGetRecI( DRBufCP, MAXFL, IDBFP, &IsDBEOF ) )
  222.     goto IOError;            /* could not read first line */
  223.  
  224.     for( ap = DRBufCP; *ap != 0; ap = sp+1 ) {
  225.     for( sp = ap; *sp && *sp != '\t'; ) sp++;
  226.     lc = *sp; *sp = 0;
  227.     DRecTF[DRecNI].FTickCP = DCDupCP( ap==sp? "date":DCLwrPkCP( ap ) );
  228.     DRecNI++;
  229.     if ( lc == 0 || DRecNI >= MAXFIELD ) break;
  230.     }
  231.  
  232.     /* --- parse labels associated with tickers --- */
  233.     if ( DBGetRecI( DRBufCP, MAXFL, IDBFP, &IsDBEOF ) )
  234.     goto IOError;            /* could not read second line */
  235.  
  236.     for( wxI= 0, ap = DRBufCP; *ap != 0; ap = sp+1 ) {
  237.     for( sp = ap; *sp && *sp != '\t'; ) sp++;
  238.     lc = *sp; *sp = 0;
  239.     DRecTF[wxI].FSymCP = DCDupCP( ap==sp? "none":DCLwrPkCP( ap ) );
  240.     wxI++;
  241.     if ( lc == 0 || wxI >= DRecNI ) break;
  242.     }
  243.  
  244.     return( 0 );            /* success */
  245. IOError:
  246.     fclose( IDBFP );
  247.     IDBFP = (FILE *)0;
  248.     DBClearInitV();
  249.     return( -1 );
  250. }
  251.  
  252. /* --- DBReadInI() ---
  253.  *    Read a record from the master data-base, parse the data fields,
  254.  *    and set up pointers in the header data structures to them.
  255.  */
  256.  
  257. int DBReadInI()        /* read a data-base record */
  258. {
  259.     char    *sp;    /* buffer pointer */
  260.     int         wxI;    /* work index */
  261.     long     dL;    /* date as a long */
  262.  
  263.     /* --- consistency check --- */
  264.     if ( IsDBEOF || IDBFP == (FILE *)0 || DRecNI == 0 ||
  265.      DRBufCP == (char *)0 )
  266.     return( -1 );            /* could not read data-base */
  267.  
  268.     /* --- read next record --- */
  269.     if ( DBGetRecI( DRBufCP, MAXFL, IDBFP, &IsDBEOF ) != 0 )
  270.     return( -1 );
  271.  
  272.     /* --- record is read, parse it into sub-fields --- */
  273.     for( wxI = 0, sp = DRBufCP; wxI < DRecNI; wxI++ ) {
  274.     while( *sp && *sp <= ' ' && *sp != '\t' )
  275.         sp++;            /* skip leading spaces */
  276.     if ( *sp != 0 )
  277.          DRecTF[wxI].FDataCP = sp;    /* point to start of field */
  278.     else DRecTF[wxI].FDataCP = "0";    /* fake zero for null fields */
  279.     while( *sp && *sp != '\t' )
  280.         sp++;            /* skip over the data */
  281.     if ( *sp != 0 ) *sp++ = 0;    /* null terminate it */
  282.     }
  283.  
  284.     /* --- fix up the date --- */
  285.     dL = Date2BinL( DRecTF[0].FDataCP );    /* get date to long */
  286.     strcpy( DBDate, Date2StrCP( dL ) );        /* fix it up */
  287.     DRecTF[0].FDataCP = &DBDate[0];        /* point to it */
  288.  
  289.     return( 0 );
  290. }
  291.  
  292. /* --- DBWriteI() ---
  293.  *    Write a new record to the master Output data-base.
  294.  *    Pick where to get data from (session or data-base).
  295.  */
  296.  
  297. int DBWriteI( ModeI )    /* write to data-base */
  298. int         ModeI;    /* 0=Header, 1=DB, 2=New Rec; 3=merge */
  299. {
  300.     int         wxI;    /* work index into data */
  301.     char    *sp;    /* string to "write" out */
  302.     IFIELD    *ifP;    /* input field pointer */
  303.     OFIELD    *ofP;    /* output field pointer */
  304.     int         flgI;    /* flag for "pass number" */
  305.     static IFIELD NullF = { "", "", "0", 0, 0 };
  306.  
  307.     /* --- sanity check --- */
  308.  
  309.     if ( ModeI < 0 || 3 < ModeI ||
  310.      CRRawBufCP == (char *)0 ||
  311.      CRecTF     == (IFIELD *)0 ||
  312.      ORecNI     == 0 ||
  313.      ODBFP      == (FILE *)0 )
  314.     return( -1 );
  315.  
  316.     /* --- write out the data fields --- */
  317.  
  318.     flgI = 0;
  319. Next:
  320.     for( wxI = 0; wxI < ORecNI; wxI++ ) {
  321.     ofP = &ORecTF[wxI];
  322.     switch( ModeI ) {
  323.     case 0: sp = flgI?ofP->FSymCP:ofP->FTickCP; break;    /* header */
  324.     case 1: ifP = ofP->FDRecTP; break;    /* db  record only */
  325.     case 2:    ifP = ofP->FCRecTP; break;    /* new record only */
  326.     case 3: ifP = ofP->FCRecTP? ofP->FCRecTP:ofP->FDRecTP; break;
  327.     }
  328.     if ( ModeI ) sp = ifP? ifP->FDataCP:"0";
  329.     if ( wxI ) fputs( "\t", ODBFP );    /* field separator */
  330.     fputs( sp, ODBFP );            /* field itself */
  331.     }
  332.     fputs( "\n", ODBFP );            /* terminal <lf> */
  333.     flgI++;                    /* next pass */
  334.     if ( ModeI == 0 && flgI == 1 ) goto Next;    /* only on header */
  335.  
  336.     return( 0 );                /* done */
  337. }
  338.  
  339. /* --- DBCloseI() ---
  340.  *    Close both the input and output data-base files.
  341.  *    Reset all of the data structures to prevent any "accidents".
  342.  */
  343.  
  344. int DBCloseI()        /* close data-bases */
  345. {
  346.     if ( IDBFP != (FILE *)0 ) { fclose( IDBFP ); IDBFP = (FILE *)0; }
  347.     if ( ODBFP != (FILE *)0 ) { fclose( ODBFP ); ODBFP = (FILE *)0; }
  348.     DBClearInitV();
  349.  
  350.     return( 0 );
  351. }
  352.  
  353. /************************************************************************
  354.  *                                    *
  355.  *            Session Parse Routines                *
  356.  *                                    *
  357.  ************************************************************************
  358.  */
  359.  
  360. /* --- Line Types --- */
  361.  
  362. int      LTypeI     = {0};    /* current line type */
  363.  
  364. #define    LT_OTHER     0    /* unclassifiable */
  365. #define    LT_SESSION     1    /* session level line */
  366. #define    LT_TICKER     2    /* ticker in line */
  367. #define    LT_FIELDS     3    /* fields & titles */
  368. #define    LT_DATA         4    /* line starts with numeric data */
  369. #define    LT_EOD         5    /* end of ticker data file */
  370.  
  371. #define    LT_BLANK     6    /* blank line */
  372. #define    LT_CONTINUE     7    /* continue type line */
  373.  
  374. /* NOTE: in a more efficient implementation, these will all be DYNAMIC */
  375.  
  376. char     Ticker[MAXTL+2] = {0};    /* ticker symbol */
  377. char     TitleL[MAXSL+2] = {0};    /* title line */
  378. char     FieldL[MAXSL+2] = {0};    /* field format line */
  379. char     LastL[MAXSL+2]  = {0};    /* save last line */
  380. char     TempL[MAXSL+2]  = {0};    /* Temporary line for data */
  381. int     LastIsFieldI     = {0};    /* last line is "fields" */
  382.  
  383. /* --- FindSubstrCP() ---
  384.  *    Find a sub-string within a longer string.
  385.  */
  386.  
  387. char *FindSubstrCP( ssp, strp )    /* returns 0 or ptr to end of sstr */
  388. char        *ssp;        /* sub-string pointer */
  389. char        *strp;        /* string pointer */
  390. {
  391.     int         ssfc;        /* first char of sub-string */
  392.     int         ssl;        /* sub-string length */
  393.     char    *csp;        /* current string pointer */
  394.  
  395.     ssfc = *ssp;            /* get first char */
  396.     ssl     = strlen( ssp );        /* length of sub-string */
  397.     for( csp = strp; (csp = strchr(csp,ssfc)) != (char *)0; csp++ ) {
  398.     if ( strncmp( csp, ssp, ssl ) == 0 )
  399.         return( &csp[ssl] );
  400.     }
  401.  
  402.     return( csp );
  403. }
  404.  
  405.  
  406. /* --- TypeLineI() ---
  407.  *    Figure out what kind of line this is.
  408.  *    If it is a "ticker line", the ticker symbol is
  409.  *    space-compressed until it is followed by a \0, or two
  410.  *    or more spaces.
  411.  */
  412.  
  413. int TypeLineI( lbp )        /* classify line */
  414. char        *lbp;        /* line buffer pointer */
  415. {
  416.     int         c;            /* work character */
  417.     int         bc;            /* blank count */
  418.     char    *sp, *dp;        /* source / destination pointer */
  419.     char    *lnbp;            /* last non-blank character */
  420.     char    *cbp;            /* current buffer pointer */
  421.  
  422.     if ( lbp == (char *)0 ) return( LT_EOD );
  423.     cbp = lbp;                /* work buffer pointer */
  424.     while( *cbp && *cbp <= ' ' ) cbp++;    /* skip spaces */
  425.     if ( *cbp == 0 )
  426.     return( LT_BLANK );        /* blank line */
  427.  
  428.     c = *cbp;
  429.     if ( '0' <= c && c <= '9' )    return( LT_DATA );    /* data ! */
  430.  
  431.     /* classify by contents */
  432.     if ( strncmp( cbp, "-----", 5 ) == 0 )
  433.     return( LT_FIELDS );
  434.  
  435.     if ( (sp = FindSubstrCP( "ticker:", cbp )) != (char *)0 ) {
  436.     /* ticker symbol, parse out the ticker symbol */
  437.     lnbp = (char *)0;
  438.     bc   = 0;
  439.     for( dp = &Ticker[0]; (c = *sp) != '\0'; sp++ ) {
  440.         if ( c > ' ' ) {
  441.         lnbp = dp;
  442.         bc = 0;
  443.         } else { bc++; }
  444.         if ( lnbp != (char *)0 && bc >= 2 ) break;
  445.         if ( c > ' ' ) *dp++ = c;
  446.     }
  447.     if ( lnbp != (char *)0 )    dp = &lnbp[1];
  448.     *dp = '\0';
  449.  
  450.     return( LT_TICKER );
  451.     }
  452.  
  453.     if ( (sp = FindSubstrCP( "press <cr> for more", cbp )) != (char *)0 )
  454.     return( LT_CONTINUE );
  455.  
  456.     if ( (sp = FindSubstrCP( "commodity:", cbp )) != (char *)0 )
  457.     return( LT_SESSION );
  458.     if ( (sp = FindSubstrCP( "issue:", cbp )) != (char *)0 )
  459.     return( LT_SESSION );
  460.     if ( (sp = FindSubstrCP( "last page",  cbp )) != (char *)0 )
  461.     return( LT_SESSION );
  462.     if ( (sp = FindSubstrCP( "compuserve", cbp )) != (char *)0 )
  463.     return( LT_SESSION );
  464.  
  465.     return( LT_OTHER );
  466. }
  467.  
  468.  
  469. /* --- GetRawSessionLineCP() ---
  470.  *    Read a line of input data from the session file.
  471.  *    Convert it to lower case, convert control chars, and 
  472.  *    pad out with trailing spaces.
  473.  */
  474.  
  475. char *GetRawSessionLineCP( ifp ) /* read next line from input session */
  476. FILE        *ifp;        /* input file pointer */
  477. {
  478.     char    *lbp;        /* line buffer pointer */
  479.     char    *rbp;        /* return buffer pointer */
  480.     char    *lnbp;        /* last non-blank pointer */
  481.  
  482.     while( (rbp = fgets(TempL,sizeof(TempL),ifp)) != (char *)0 ) {
  483.     lnbp = (char *)0;
  484.     for( lbp = rbp; *lbp != 0; lbp++ ) {
  485.         if ( *lbp <= ' ' ) *lbp = ' ';
  486.         else {
  487.         if ( 'A' <= *lbp && *lbp <= 'Z' ) *lbp -= 'A'-'a';
  488.         lnbp = lbp;
  489.         }
  490.     }
  491.     if ( lnbp != (char *)0 ) {
  492.         while( ++lnbp < &TempL[sizeof(TempL)-1] )
  493.         *lnbp = ' ';        /* pad out with spaces */
  494.         *lnbp = 0;
  495.         return( rbp );
  496.     }
  497.     }
  498.  
  499.     return( rbp );        /* EOF or error */
  500. }
  501.  
  502. /* --- GetSessionLineI() ---
  503.  *    Reads & classifies session line.
  504.  *    Saves ticker in Ticker[].
  505.  *    Saves Titles in TitleL[].
  506.  *    Saves Fields in FieldL[].
  507.  *    Works with data in TempL[].  Also uses "LastL[]" to save data.
  508.  */
  509.  
  510. int GetSessionLineI( ifp )    /* get classified session line */
  511. FILE        *ifp;        /* input file pointer */
  512. {
  513.     FILE    *ofp;        /* output file pointer */
  514.     char    *lp;        /* line pointer */
  515.     int         lt;        /* line type */
  516.     int         rc;        /* return code */
  517.     int         lc;        /* line count (from ticker) */
  518.     static char     CurTic[MAXTL+2]={0};  /* work ticker line */
  519.  
  520.     rc  = 0;                    /* good return code */
  521.     for(;;) {
  522.     lp = GetRawSessionLineCP( ifp );    /* read next line */
  523.     switch( TypeLineI( lp ) ) {        /* classify the line */
  524.     default:                /* --- should not happen --- */
  525.     case LT_OTHER:                /* not classifiable */
  526.         memmove( (void *)&LastL[0], (void *)&TempL[0], sizeof(LastL) );
  527.         return( LT_OTHER );
  528.  
  529.     case LT_SESSION:            /* session line */
  530.     SESSION:
  531.         CurTic[0] = 0;
  532.         return( LT_SESSION );
  533.  
  534.     case LT_TICKER:                /* ticker line */
  535.     GotTicker:
  536.         strcpy( CurTic, Ticker );
  537.         return( LT_TICKER );
  538.  
  539.     case LT_FIELDS:                /* fields */
  540.         memmove( (void *)&FieldL[0], (void *)&TempL[0], sizeof(FieldL) );
  541.         memmove( (void *)&TitleL[0], (void *)&LastL[0], sizeof(TitleL) );
  542.         return( LT_FIELDS );        /* we got titles & fields */
  543.  
  544.     case LT_DATA:                /* valid data line */
  545.         return( LT_DATA );
  546.  
  547.     case LT_EOD:                /* end of file */
  548.     EOD:
  549.         LastL[0] = TempL[0] = 0;        /* kill work lines */
  550.         CurTic[0] = 0;            /* kill existing ticker */
  551.         return( LT_EOD );
  552.  
  553.     case LT_BLANK:                /* blank line */
  554.         continue;
  555.  
  556.     case LT_CONTINUE:
  557.         /* --- must find: EOD, Data, Session, or Ticker --- */
  558.         for(;;) {        /* scan for a terminal, skip blanks */
  559.         lp = GetRawSessionLineCP( ifp ); /* next input line */
  560.         switch( TypeLineI( lp ) ) {    /* classify and act */
  561.         case LT_EOD:        goto EOD;
  562.         case LT_DATA:        return( LT_DATA );
  563.         case LT_SESSION:    goto SESSION;
  564.         case LT_TICKER:
  565.             if ( strcmp( Ticker, CurTic ) != 0 )
  566.             goto GotTicker;
  567.         }
  568.         }
  569.     }
  570.     }
  571. }
  572.  
  573. /* --- InputFormatI() ---
  574.  *    Figure out the input format and build up the appropriate
  575.  *    data structures.
  576.  *    NOTE: data-base open initialized all structures.
  577.  */
  578.  
  579. int InputFormatI()
  580. {
  581.     char    *sp, *ap;    /* work string pointers */
  582.     int         stI, lnI;    /* start offset, length */
  583.     int         wxI;        /* work index */
  584.     IFIELD    *ifP;        /* input field pointer */
  585.  
  586.     DCLwrPkCP( Ticker );    /* scrunch the ticker just in case */
  587.     sp = &FieldL[0];        /* field definitions line */
  588.     for( wxI = 0; wxI < MAXFIELD; wxI++ ) {
  589.     ifP = &CRecTF[CRecNI];            /* current field descriptor */
  590.     while( *sp && *sp <= ' ' ) sp++;    /* skip leading spaces */
  591.     stI = (sp - &FieldL[0]);        /* start position */
  592.     if ( *sp != '-' && *sp != '=' ) break;    /* end of fields */
  593.  
  594.     while( *sp == '-' || *sp == '=' ) sp++;    /* parse field itself */
  595.     lnI = (sp - &FieldL[0]) - stI;        /* length of field */
  596.     TitleL[ stI+lnI ] = 0;            /* null terminate title */
  597.     ifP->FTickCP = DCDupCP( Ticker );    /* ticker */
  598.     ifP->FSymCP  = DCDupCP(DCLwrPkCP(&TitleL[stI])); /* title */
  599.     ifP->FStartI = stI;            /* start */
  600.     ifP->FLenI   = lnI;            /* length */
  601.     ifP->FDataCP = (char *)0;        /* current data */
  602.     CRecNI++;                /* next field */
  603.     }
  604.     return( 0 );
  605. }
  606.  
  607.  
  608. /* --- OFCmpI() ---
  609.  *    Compare routine for sorting data-base output fields
  610.  */
  611.  
  612. int OFCmpI( pa, pb )
  613. void        *pa, *pb;    /* input pointers */
  614. {
  615.     OFIELD    *oa, *ob;    /* field pointers */
  616.     int         rc;        /* return code */
  617.  
  618.     oa = (OFIELD *)pa;
  619.     ob = (OFIELD *)pb;
  620.     if ( (rc = strcmp( oa->FTickCP, ob->FTickCP )) == 0 )
  621.     rc = strcmp( oa->FSymCP, ob->FSymCP );
  622.     return( rc );
  623. }
  624.  
  625. /* --- OutputFormatI() ---
  626.  *    Create merged data structures
  627.  */
  628.  
  629. int OutputFormatI()    /* create merged data structures */
  630. {
  631.     int         dxI;    /* data-base input index */
  632.     int         cxI;    /* current input index */
  633.     int         wxI;    /* work index */
  634.     IFIELD    *ifP;    /* input field pointer */
  635.     OFIELD    *ofP;    /* output field pointer */
  636.     char    *tCP;    /* ticker pointer */
  637.     char    *fCP;    /* field name pointer */
  638.  
  639.     /* --- copy to data-base to output description --- */
  640.  
  641.     for( dxI = 0; dxI < DRecNI; dxI++ ) {
  642.     ifP = &DRecTF[dxI];
  643.     ofP = &ORecTF[ORecNI];
  644.     ofP->FTickCP = ifP->FTickCP;
  645.     ofP->FSymCP  = ifP->FSymCP;
  646.     ofP->FDRecTP = ifP;
  647.     ofP->FCRecTP = (IFIELD *)0;
  648.     ORecNI++;
  649.     }
  650.  
  651.     /* --- merge new input record into output description --- */
  652.  
  653.     for( cxI = DRecNI?1:0; cxI < CRecNI; cxI++ ) {
  654.     ifP = &CRecTF[cxI];
  655.     tCP = ifP->FTickCP;
  656.     fCP = ifP->FSymCP;
  657.     ofP = &ORecTF[0];
  658.     for( wxI = 0; wxI < ORecNI; wxI++, ofP++ ) {
  659.         /* --- determine if it is already in output --- */
  660.         if ( tCP == ofP->FTickCP && fCP == ofP->FSymCP ) {
  661.         ofP->FCRecTP = ifP;
  662.         break;
  663.         }
  664.     }
  665.  
  666.     if ( wxI >= DRecNI ) {
  667.         ofP = &ORecTF[ORecNI];    /* append record */
  668.         ofP->FTickCP = ifP->FTickCP;
  669.         ofP->FSymCP  = ifP->FSymCP;
  670.         ofP->FDRecTP = (IFIELD *)0;
  671.         ofP->FCRecTP = ifP;
  672.         ORecNI++;            /* record addition */
  673.     }
  674.     }
  675.     ORecTF[0].FTickCP = "";        /* null ticker for date */
  676.     ORecTF[0].FCRecTP = &CRecTF[0];    /* date field for merge record */
  677.  
  678.     /* --- Sort data into sequence --- */
  679.  
  680.     qsort( (void *)&ORecTF[1], ORecNI-1, sizeof(OFIELD), OFCmpI );
  681.  
  682.     /* --- all done, return --- */
  683.  
  684.     return( 0 );
  685. }
  686.  
  687. /* --- ParseSessionLineI() ---
  688.  *    Parse a line of session data, reformatting it as required
  689.  *    and updating the input data structures.
  690.  */
  691.  
  692. int ParseSessionLineI( )    /* parse a session line */
  693. {
  694.     IFIELD    *ifP;        /* input field pointer */
  695.     long     dL;        /* date in "long" format */
  696.     char    *sp, *dp;    /* work string pointers */
  697.     char    *aCP;        /* alternate "clean" buffer */
  698.     double     rv;        /* real value */
  699.     int         wxI;        /* work index */
  700.  
  701.     /* --- set up pointers to each of the data items --- */
  702.  
  703.     for( wxI = 0; wxI < CRecNI; wxI++ ) {
  704.     ifP = &CRecTF[wxI];        /* definition of this string */
  705.     sp  = &TempL[ifP->FStartI];    /* start of string */
  706.     sp[ifP->FLenI] = 0;        /* end of string */
  707.     while( *sp && *sp<=' ' ) sp++;    /* remove leading spaces */
  708.     ifP->FDataCP = sp;        /* point to the string */
  709.     for( dp = (char *)0; *sp != 0; sp++ )
  710.         if ( *sp > ' ' ) dp = sp;
  711.     if ( dp != (char *)0 ) dp[1] = 0;    /* truncate trailing spaces */
  712.     }
  713.  
  714.     /* --- make the date into consistent format --- */
  715.  
  716.     dL = Date2BinL( CRecTF[0].FDataCP );
  717.     strcpy( CRDate, Date2StrCP( dL ) );
  718.     CRecTF[0].FDataCP = CRDate;        /* update formated date */
  719.  
  720.     /* --- fix up all of the numeric fields in the record --- */
  721.  
  722.     aCP = &CRBufCP[0];        /* current record "work" buffer */
  723.     for( wxI = 1; wxI < CRecNI; wxI++ ) {
  724.     ifP = &CRecTF[wxI];    /* definition of this string */
  725.     if ( *(ifP->FDataCP) == 0 ) ifP->FDataCP = "0";
  726.     else {
  727.         rv  = Asc2NumD( ifP->FDataCP, ifP->FLenI );
  728.         sprintf( aCP, "%.4f", rv );    /* new number */
  729.         for( dp = &aCP[strlen(aCP)-1]; dp > aCP; dp-- ) {
  730.         if ( *dp == '0' ) { *dp = 0; continue; }
  731.         if ( *dp == '.' )   *dp = 0;
  732.         break;
  733.         }
  734.         ifP->FDataCP = aCP;
  735.         aCP += strlen( aCP ) + 1;
  736.     }
  737.     }
  738.     return( 0 );
  739. }
  740.  
  741. /* --- ProcessSessionI() ---
  742.  *    Process an input session merging the data into the master
  743.  *    data-base.
  744.  */
  745.  
  746. int ProcessSessionI( sesfnCP, dbfnCP )    /* Process Session file */
  747. char        *sesfnCP;    /* name of session file to open */
  748. char        *dbfnCP;    /* data-base file name */
  749. {
  750.     FILE    *sFP=(FILE *)0;    /* session file pointer */
  751.     int         stateI;    /* state of processing */
  752.     int         typeI;        /* type of line from input session */
  753.     int         flagI;        /* flag for where we are (state) */
  754.     long     CRCDateL;    /* current record date */
  755.     long     CDBDateL;    /* current data-base date */
  756.     static char     TempFN[] = {"temp.db"};    /* work file */
  757.  
  758.     memset( (void *)&Ticker[0], 0, sizeof(Ticker) );
  759.     memset( (void *)&TitleL[0], 0, sizeof(TitleL) );
  760.     memset( (void *)&FieldL[0], 0, sizeof(FieldL) );
  761.     memset( (void *)&LastL[0],  0, sizeof(LastL)  );
  762.     memset( (void *)&TempL[0],  0, sizeof(TempL)  );
  763.  
  764.     if ( (sFP = fopen( sesfnCP, "r" )) == (FILE *)0 ) {
  765.     fprintf( stderr, "Could not open session file <%s>\n", sesfnCP );
  766.     return( -1 );
  767.     }
  768.  
  769.     stateI = 0;        /* initial state */
  770.     for(;;) {        /* search for ticker */
  771.     while( stateI != 2 ) {
  772.         switch( GetSessionLineI( sFP ) ) {
  773.         default:
  774.         case LT_OTHER:                break;
  775.         case LT_SESSION:    stateI = 0;        break;
  776.         case LT_TICKER:    stateI = 1;        break;
  777.         case LT_FIELDS:    stateI = stateI==1?2:0;    break;
  778.         case LT_DATA:    stateI = 0;        break;
  779.         case LT_EOD:                goto EOD;
  780.         }
  781.     }
  782.     /* --- Ticker, Titles & Fields are all valid --- */
  783.     /* --- Open Master Data-Base for input & output --- */
  784.  
  785.     fprintf( stderr, "Processing ticker <%s> in file <%s>\n",
  786.         Ticker, sesfnCP );
  787.  
  788.     if ( DBOpenInI( dbfnCP ) != 0 ) {
  789.         fprintf( stderr, "Could not open input data-base <%s>\n", dbfnCP );
  790.         fprintf( stderr, "Creating new data-base\n" );
  791.     }
  792.  
  793.     if ( (ODBFP = fopen( TempFN, "w" )) == (FILE *)0 ) {
  794.         fprintf( stderr, "Could not open temp data-base <%s>\n", TempFN );
  795.         break;
  796.     }
  797.  
  798.     /* --- Build input data Structures --- */
  799.     InputFormatI();
  800.  
  801.     /* --- Create merged data Structures --- */
  802.     OutputFormatI();
  803.     DBWriteI( 0 );        /* write out header */
  804.  
  805.     /* --- Read first record of data-base --- */
  806.     DBReadInI();
  807.     CDBDateL = IsDBEOF? 0L:Date2BinL( DRecTF[0].FDataCP );
  808.  
  809.     for( stateI = 0; stateI == 0;) {
  810.         switch( (typeI = GetSessionLineI( sFP )) ) {
  811.         case LT_EOD:
  812.         case LT_SESSION:
  813.         case LT_TICKER:    stateI = 1;     continue;
  814.         case LT_FIELDS:
  815.         case LT_OTHER:            continue;
  816.         case LT_DATA:
  817.         ParseSessionLineI();        /* parse the data */
  818.         CRCDateL = Date2BinL( CRecTF[0].FDataCP );
  819.         while( IsDBEOF == 0 && CRCDateL > CDBDateL ) {
  820.             DBWriteI( 1 );    /* write data-base record */
  821.             DBReadInI();
  822.             CDBDateL = IsDBEOF? 0L:Date2BinL( DRecTF[0].FDataCP );
  823.         }
  824.  
  825.         if ( IsDBEOF || CRCDateL < CDBDateL ) {
  826.             DBWriteI( 2 );    /* write input record */
  827.         } else if ( CRCDateL == CDBDateL ) {
  828.             DBWriteI( 3 );    /* write merged record */
  829.             DBReadInI();    /* read next db record */
  830.             CDBDateL = IsDBEOF? 0L:Date2BinL( DRecTF[0].FDataCP );
  831.         }
  832.         }
  833.     }
  834.  
  835.     while( !IsDBEOF ) {
  836.         DBWriteI( 1 );        /* write data-base record */
  837.         DBReadInI();        /* read next record */
  838.     }
  839.     if ( ferror( ODBFP ) ) {
  840.         fprintf( stderr, "Errors closing temp data-base.  Not Updated.\n" );
  841.         flagI = 1;
  842.     } else flagI = 0;
  843.     DBCloseI();            /* close data-bases */
  844.     if ( flagI == 0 ) {
  845.         unlink( dbfnCP );        /* kill old file */
  846.         rename( TempFN, dbfnCP );    /* replace with new */
  847.     }
  848.  
  849.     /* --- Determine how to proceed forward --- */
  850.     if ( typeI == LT_EOD ) break;        /* exit on EOF */
  851.  
  852.     stateI = typeI == LT_TICKER?1:0;    /* set current state */
  853.     }
  854. EOD:
  855.     if ( sFP != (FILE *)0 ) fclose( sFP );
  856.     DBClearInitV();
  857.     return( 0 );
  858. }
  859.  
  860. /* --- main() ---
  861.  *    Main Driver program for data-base manager
  862.  *
  863.  *    Command line format:
  864.  *        finbld dbase session session session ...
  865.  */
  866.  
  867. main( ac, av )
  868. int         ac;    /* # of arguments */
  869. char        *av[];    /* list of arguments */
  870. {
  871.     int         wI;    /* work index */
  872.  
  873.     if ( ac < 3 ) {
  874.     fprintf( stderr, "USE: FINBLD data_base session [session..]\n" );
  875.     exit( 1 );
  876.     }
  877.  
  878.     for( wI = 2; wI < ac; wI++ )
  879.     ProcessSessionI( av[wI], av[1] );
  880.  
  881.     exit( 0 );
  882. }
  883.